<?php

/**
 * Data Acess Object
 * 
 * Classe responsável pelo tratamento do banco de dados utilizando
 * a API do Doctrine.
 * 
 * @author Cristiano M. Gomes <cmgomes.es@gmail.com>
 */
class Dao{

	/**
	 * Singleton do objeto
	 */
	 static private $instancia;  	

	/**
	 * Conexão Doctrine
	 */  
	 private $conn;

	 /**
	  * Método construtor, a única função executada aqui é a de conectar ao banco de dados
	  */
	 function __construct(){}

	 /**
	  * Prefixo que o sistema usará nos nomes das tabelas do banco de dados
	  * 
	  * @var string
	  */
	 private $prefixo;
	 
	 /**
	  * Configura o prefixo das tabelas do banco de dados
	  * @param string
	  */
	 public function set_prefixo($pre){
	 	$this->prefixo = $pre;
	 }
	 
	 /**
	  * Retorna o prefixo das tabelas do banco de dados
	  * @param string
	  */
	 public function get_prefixo(){
	 	return $this->prefixo;
	 }

	/**
	  * Retorna a conexão atual do doctrine com o banco de dados
	  *
	  * @return Doctrine_Connection
	  */ 
 	public function get_conexao(){
		return $this->conn;
	}

	/**
	 * Instancia o Doctrine, seta alguns parametros iniciais e estabelece a conexão
	 * com o banco de dados.
	 * 
	 * @return void
	 */  
	 public function Conectar(){
	 	if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->Start("Dao::Conectar");

	 	try{
	 		
	 		$manager = Doctrine_Manager::getInstance();
	 		
		 	$manager->setAttribute(Doctrine::ATTR_USE_DQL_CALLBACKS, true);
		 	if($this->prefixo){
		 		$this->set_prefixo_tabela($this->prefixo);
		 	}
			
		 	$this->conn = Doctrine_Manager::connection($this->GetStrConexao());
		 	$this->conn->setCharset('utf8');
			$this->conn->setCollate('utf8_general_ci');

	 	}catch (Exception $e){
	 		die($e->getMessage() . "<br />StackTrace: <br />" . $e->getTraceAsString());
	 	}
	 	

		
		if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->End("Dao::Conectar");
	}

	/**
	 * Converte os dados de conexão para formato string aceito pelo doctrine
	 * 
	 * @return string
	 */ 
	private function GetStrConexao(){
		if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->Start("Dao::GetStrConexao");
		
		$db = Sistema::GetInstancia()->GetDatabase();
		$string = "{$db->DbType()}://{$db->Usuario()}:{$db->Senha()}@{$db->Host()}:{$db->Porta()}/{$db->Base()}";
		
		if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->End("Dao::GetStrConexao");
		return $string;
	}

	/**
	 * Manipula a instancia singleton da classe
	 * 
	 * @return Dao
	 */ 
	public static function GetInstancia(){
		if(!Dao::$instancia) Dao::$instancia = new Dao;
		return Dao::$instancia;
	}

    /**
     * Adiciona um prefixo aos nomes das tabelas
     * @param String $prefix
     */
    public function set_prefixo_tabela($prefixo) {
        $manager = Doctrine_Manager::getInstance();
        $manager->setAttribute(Doctrine::ATTR_TBLNAME_FORMAT, $prefixo . '%s');
    }

	/**
	 * Cria tabela no banco de dados usando ou Array de classes Modelos
	 * 
	 * @param mixed Array
	 */ 
    public function criar_tabela(array $classes){
		$modelos = array();
        if (is_array($classes) && sizeof($classes) > 0) {
            foreach ($classes as $classe) {
                $modelo = new $classe;
                $modelos[] = $classe;
                unset($modelo);
            }
        }
        if (sizeof($modelos) > 0) {
            Doctrine::createTablesFromArray($modelos);
        }
	}

	/**
	 * Retorna o último id registrado no banco de dados
	 *  
	 * @return Integer 
	 */ 
	public function pega_ultimo_id() {
        return $this->get_conn()->lastInsertId();
    }

	/**
	 * Com base no modelo enviado, busca o modelo que possui o id passado
	 * 
	 * @param Modelo
	 * @param Integer
	 * @return Modelo
	 */ 
    public function busca_por_id($modelo, $id) {
        $class = $modelo;
        if ($modelo instanceof Modelo) {
            $class = get_class($modelo);
        }
        $table = Doctrine::getTable($class);
        return $table->find($id);
    }

    /**
     * Limpa tabela enviada resetando o indice do banco de dados.
     * @param Modelo
     * @param String
     * 
     * @return boolean
     * @throws Exception
     * 
     */
    public function truncate($modelo, $sequencia = ''){
    	if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->Start("Dao::truncate");
    	
    	$classe = $modelo;
        if ($modelo instanceof Modelo){
            $classe = get_class($modelo);
        }

        $tabela = Doctrine::getTable($classe)->getTableName();
    	$doctrine = Doctrine_Manager::getInstance()->getCurrentConnection()->getDbh();

    	try {
    		if($sequencia != ''){
    			$doctrine->query("TRUNCATE TABLE $tabela");//
    			$doctrine->query("ALTER SEQUENCE $sequencia RESTART WITH 1");
    		}else{
    			$doctrine->query("TRUNCATE TABLE $tabela;");
    			$doctrine->query("ALTER SEQUENCE {$tabela}_id_seq RESTART WITH 1");
    		}
            unset($doctrine);
            
    	} catch (Exception $e) {
            throw new Exception($e->getMessage(), $e->getCode());
        }

        if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->End("Dao::truncate");
        return true;
    }

    /**
     * Registra a entidade passada por parametro no banco dedados. Em caso de erro,
     * lança exception.
     * 
     * @param Modelo
     * @throws Exception
     */
    public function salvar(Modelo $modelo){
    	if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->Start("Dao::salvar");
    	
        try {
            // atualizando o modelo
            if($modelo->get_id() != null && $modelo->identifier() > 0) {
                $modelo->set_data_modificacao(date('Y-n-d H:i:s'));
            }
            // persistindo pela primeira vez (id == null)
            else{
                $modelo->set_data_criacao(date('Y-n-d H:i:s'));
                $modelo->set_data_modificacao(null);
                $modelo->set_deletado(false);
                $modelo->set_publicado(false);
            }
            $modelo->save();
            
            if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->End("Dao::salvar");
            return $modelo;
        } catch (Exception $e) {
        	
        	if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->End("Dao::salvar");
            throw new Exception($e->getMessage(), $e->getCode());
        }
    }

    /**
     * Cria Doctrine_query para buscas usando linguagem DQL
     * Vide Manual Doctrine
     *
     * @return Doctrine_Query
     */
	public function CriaQuery() {
		//Utils::PrintArray($this->conn);
		//die();
        return $this->conn->createQuery();
    }

    /**
     * Deleta o registro do banco de dados 
     *
     * @param Modelo
     */
    public function deletar(Modelo $modelo) {
    	if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->Start("Dao::deletar");

        $modelo->set_deletado(true);
        $modelo->set_data_modificacao(Utils::TimestampAtual());
        $modelo->save();

        if(Sistema::GetInstancia()->GetMedidor()) Velocimetro::GetInstancia()->End("Dao::deletar");
    }
}